Module modRecent
    Private dictRecent As New Dictionary(Of String, String)
    Private Const RESULT_SPLITTER As String = Chr(0) ' Separates different result combinations in the my.settings string
    Private Const KEYVAL_SPLITTER As String = Chr(1) ' Separates key = value combinations in individual results strings

    Public Sub loadRecentResults()
        ' Purpose:
        '   Go to application settings, and load what's stored there into our recent results dictionary

        Dim strRecentResults As String = My.Settings.strRecentResults
        Dim strResultArr() As String
        Dim strKeyVal() As String

        ' If nothing stored or invalid splitter, skip entire process
        If InStr(strRecentResults, RESULT_SPLITTER) = 0 Then Exit Sub

        strResultArr = strRecentResults.Split(RESULT_SPLITTER)

        For intCounter As Integer = 0 To strResultArr.GetUpperBound(0)
            If InStr(strResultArr(intCounter), KEYVAL_SPLITTER) > 0 Then
                strKeyVal = strResultArr(intCounter).Split(KEYVAL_SPLITTER)

                ' Got key/value combination, add to dictionary
                addMatch(strKeyVal(0), strKeyVal(1))
            Else
                ' Not valid result, ignore
            End If
        Next
    End Sub

    Public Sub prepareToSaveRecent()
        ' Preconditions:
        '   Called from event handler used for handling "before save" event of my.settings
        ' Purpose:
        '   Update the settings as appropriate, converting dictionary to a single string

        Dim strSetting As String = vbNullString

        ' If nothing to save, then do nothing
        If dictRecent.Count = 0 Then Exit Sub

        For Each Key As String In dictRecent.Keys
            strSetting = strSetting & Key & KEYVAL_SPLITTER & dictRecent(Key) & RESULT_SPLITTER
        Next

        ' Remove final result splitter
        strSetting = strSetting.TrimEnd(RESULT_SPLITTER)

        My.Settings.strRecentResults = strSetting
    End Sub

    Public Sub addMatch(ByVal strSearch As String, ByVal strResult As String)
        ' Preconditions:
        '   strSearch = Character user entered
        '   strResult = Character user clicked after searching for strSearch
        ' Purpose:
        '   Add that the user clicked this result to our running storage of
        '       preferred results

        If dictRecent.ContainsKey(strSearch) Then
            ' There are recent results for this search string already

            ' Take new result remove it if it exists from the list and push it to the front
            dictRecent(strSearch) = strResult & dictRecent(strSearch).Replace(strResult, vbNullString)
        Else
            ' Nothing in the dictionary containing results for this search, create new entry
            dictRecent.Add(strSearch, strResult)
        End If
    End Sub

    Public Function getMatches(ByVal strSearch As String) As String
        ' Purpose:
        '   Returns matches given a search string if any exists
        ' Postconditions:
        '   Returns Null String if no results in existance yet
        '   Returns matches if results exist

        If dictRecent.ContainsKey(strSearch) Then
            Return dictRecent(strSearch)
        Else
            Return vbNullString
        End If

    End Function

    Public Function getFinalResultsList(ByVal strSearch As String, ByVal strRawResults As String) As String
        ' Purpose:
        '   Given a search string and raw results, give the results by adjusting
        '   the result order so recent items are at front of string, less recent items at rear

        Dim strMatches As String
        strMatches = getMatches(strSearch)  ' Grab results of previously used characters

        If strMatches = vbNullString Then
            ' If nothing to change, just return what we received
            Return strRawResults
        Else
            ' Convert the raw match string to an array of strings each containing 1 character
            Dim intUBound As Integer = strMatches.Length - 1
            Dim strMatchArray(intUBound) As String

            For intCounter As Integer = 0 To intUBound
                strMatchArray(intCounter) = strMatches.Substring(intCounter, 1)

                If InStr(strRawResults, strMatchArray(intCounter)) = 0 Then
                    ' Wait, what was found is not part of the result set
                    '   Security: File-tampering suspected!
                    removeMatch(strSearch, strMatchArray(intCounter))


                    ' Re-try processing from scratch again
                    Return getFinalResultsList(strSearch, strRawResults)
                    Exit Function
                End If
            Next

            ' Okay, everything is clean now... Now alter results
            Dim strNewResults As String = strRawResults

            ' Process array in reverse order so most recent (at top of array) will be first
            For intCounter As Integer = intUBound To 0 Step -1
                ' Remove from rest of results and push to top
                strNewResults = strMatchArray(intCounter) & strNewResults.Replace(strMatchArray(intCounter), vbNullString)
            Next

            ' Return the new results
            Return strNewResults
        End If

    End Function

    Private Sub removeMatch(ByVal strSearch As String, ByVal strToRemove As String)
        ' Purpose:
        '   Removes any match that is determined by another function to be invalid (or result of file corruption/tampering)

        dictRecent(strSearch) = dictRecent(strSearch).Replace(strToRemove, vbNullString)

        ' If nothing left in results string, remove from dictionary
        If dictRecent(strSearch) = vbNullString Then
            dictRecent.Remove(strSearch)
        End If
    End Sub


End Module
